{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "from numpy import *"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "def loadDataSet(fileName):\n",
    "    dataMat = []\n",
    "    fr = open(fileName)\n",
    "    for line in fr.readlines():\n",
    "        curLine = line.strip().split('\\t')\n",
    "        fltLine = list(map(float, curLine))\n",
    "        dataMat.append(fltLine)\n",
    "    return dataMat\n",
    "\n",
    "# 切分数据集\n",
    "def binSplitDataSet(dataSet, feature, value):\n",
    "    # nonzero 返回非零元素的位置，表示为两行值，第一行为行号，第二行是列号\n",
    "    mat0 = dataSet[nonzero(dataSet[:, feature] > value)[0], :]\n",
    "    mat1 = dataSet[nonzero(dataSet[:, feature] <= value)[0], :]\n",
    "    return mat0, mat1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[1., 0., 0., 0.],\n",
       "        [0., 1., 0., 0.],\n",
       "        [0., 0., 1., 0.],\n",
       "        [0., 0., 0., 1.]])"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "testMat = mat(eye(4))\n",
    "testMat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[0., 1., 0., 0.]])"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mat0, mat1 = binSplitDataSet(testMat, 1, 0.5)\n",
    "mat0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[1., 0., 0., 0.],\n",
       "        [0., 0., 1., 0.],\n",
       "        [0., 0., 0., 1.]])"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "mat1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "### 回归树的切分函数\n",
    "# 负责生成叶节点\n",
    "def regLeaf(dataSet):\n",
    "    return mean(dataSet[:, -1])\n",
    "\n",
    "# 总方差\n",
    "def regErr(dataSet):\n",
    "    return var(dataSet[:, -1]) * shape(dataSet)[0]\n",
    "\n",
    "# 找到最佳二元切分方式，若找不到则返回None并创建叶节点，否则返回特征编号和切分特征值\n",
    "def chooseBestSplit(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):\n",
    "    tolS = ops[0]  # 容许的误差下降值\n",
    "    tolN = ops[1]  # 切分的最少样本数\n",
    "    if len(set(dataSet[:, -1].T.tolist()[0])) == 1:\n",
    "        return None, leafType(dataSet)\n",
    "\n",
    "    m, n = shape(dataSet)\n",
    "    S = errType(dataSet)  # 误差\n",
    "    bestS = inf\n",
    "    bestIndex = 0\n",
    "    bestValue = 0\n",
    "    for featIndex in range(n-1):\n",
    "        for splitVal in set((dataSet[:,featIndex].T.A.tolist())[0]):\n",
    "            mat0, mat1 = binSplitDataSet(dataSet, featIndex, splitVal)\n",
    "            if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN):\n",
    "                continue\n",
    "            newS = errType(mat0) + errType(mat1)\n",
    "            if newS < bestS:\n",
    "                bestIndex = featIndex\n",
    "                bestValue = splitVal\n",
    "                bestS = newS\n",
    "    if S - bestS < tolS:\n",
    "        return None, leafType(dataSet)\n",
    "    mat0, mat1 = binSplitDataSet(dataSet, bestIndex, bestValue)\n",
    "    if (shape(mat0)[0] < tolN) or (shape(mat1)[0] < tolN):\n",
    "        return None, leafType(dataSet)\n",
    "    return bestIndex, bestValue\n",
    "\n",
    "def createTree(dataSet, leafType=regLeaf, errType=regErr, ops=(1, 4)):\n",
    "    feat, val = chooseBestSplit(dataSet, leafType, errType, ops)\n",
    "    if feat == None:\n",
    "        return val\n",
    "    \n",
    "    retTree = {}\n",
    "    retTree['spInd'] = feat\n",
    "    retTree['spVal'] = val\n",
    "    lSet, rSet = binSplitDataSet(dataSet, feat, val)\n",
    "    retTree['left'] = createTree(lSet, leafType, errType, ops)\n",
    "    retTree['right'] = createTree(rSet, leafType, errType, ops)\n",
    "    return retTree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'spInd': 0,\n",
       " 'spVal': 0.48813,\n",
       " 'left': 1.0180967672413792,\n",
       " 'right': -0.04465028571428572}"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "myDat = loadDataSet('ex00.txt')\n",
    "myMat = mat(myDat)\n",
    "createTree(myMat)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'spInd': 1,\n",
       " 'spVal': 0.39435,\n",
       " 'left': {'spInd': 1,\n",
       "  'spVal': 0.582002,\n",
       "  'left': {'spInd': 1,\n",
       "   'spVal': 0.797583,\n",
       "   'left': 3.9871632,\n",
       "   'right': 2.9836209534883724},\n",
       "  'right': 1.980035071428571},\n",
       " 'right': {'spInd': 1,\n",
       "  'spVal': 0.197834,\n",
       "  'left': 1.0289583666666666,\n",
       "  'right': -0.023838155555555553}}"
      ]
     },
     "execution_count": 9,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "myDat1 = loadDataSet('ex0.txt')\n",
    "myMat1 = mat(myDat1)\n",
    "createTree(myMat1)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 树剪枝"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'spInd': 0,\n",
       " 'spVal': 0.499171,\n",
       " 'left': {'spInd': 0,\n",
       "  'spVal': 0.729397,\n",
       "  'left': {'spInd': 0,\n",
       "   'spVal': 0.952833,\n",
       "   'left': {'spInd': 0,\n",
       "    'spVal': 0.958512,\n",
       "    'left': 105.24862350000001,\n",
       "    'right': 112.42895575000001},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.759504,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.790312,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.833026,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.944221,\n",
       "       'left': 87.3103875,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.85497,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.910975,\n",
       "         'left': 96.452867,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.892999,\n",
       "          'left': 104.825409,\n",
       "          'right': {'spInd': 0,\n",
       "           'spVal': 0.872883,\n",
       "           'left': 95.181793,\n",
       "           'right': 102.25234449999999}}},\n",
       "        'right': 95.27584316666666}},\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.811602,\n",
       "       'left': 81.110152,\n",
       "       'right': 88.78449880000001}},\n",
       "     'right': 102.35780185714285},\n",
       "    'right': 78.08564325}},\n",
       "  'right': {'spInd': 0,\n",
       "   'spVal': 0.640515,\n",
       "   'left': {'spInd': 0,\n",
       "    'spVal': 0.666452,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.706961,\n",
       "     'left': 114.554706,\n",
       "     'right': {'spInd': 0,\n",
       "      'spVal': 0.698472,\n",
       "      'left': 104.82495374999999,\n",
       "      'right': 108.92921799999999}},\n",
       "    'right': 114.1516242857143},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.613004,\n",
       "    'left': 93.67344971428572,\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.582311,\n",
       "     'left': 123.2101316,\n",
       "     'right': {'spInd': 0,\n",
       "      'spVal': 0.553797,\n",
       "      'left': 97.20018024999999,\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.51915,\n",
       "       'left': {'spInd': 0,\n",
       "        'spVal': 0.543843,\n",
       "        'left': 109.38961049999999,\n",
       "        'right': 110.979946},\n",
       "       'right': 101.73699325000001}}}}}},\n",
       " 'right': {'spInd': 0,\n",
       "  'spVal': 0.457563,\n",
       "  'left': {'spInd': 0,\n",
       "   'spVal': 0.467383,\n",
       "   'left': 12.50675925,\n",
       "   'right': 3.4331330000000007},\n",
       "  'right': {'spInd': 0,\n",
       "   'spVal': 0.126833,\n",
       "   'left': {'spInd': 0,\n",
       "    'spVal': 0.373501,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.437652,\n",
       "     'left': -12.558604833333334,\n",
       "     'right': {'spInd': 0,\n",
       "      'spVal': 0.412516,\n",
       "      'left': 14.38417875,\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.385021,\n",
       "       'left': -0.8923554999999995,\n",
       "       'right': 3.6584772500000016}}},\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.335182,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.350725,\n",
       "      'left': -15.08511175,\n",
       "      'right': -22.693879600000002},\n",
       "     'right': {'spInd': 0,\n",
       "      'spVal': 0.324274,\n",
       "      'left': 15.05929075,\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.297107,\n",
       "       'left': -19.9941552,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.166765,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.202161,\n",
       "         'left': {'spInd': 0,\n",
       "          'spVal': 0.217214,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.228473,\n",
       "           'left': {'spInd': 0,\n",
       "            'spVal': 0.25807,\n",
       "            'left': 0.40377471428571476,\n",
       "            'right': -13.070501},\n",
       "           'right': 6.770429},\n",
       "          'right': -11.822278500000001},\n",
       "         'right': 3.4496025},\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.156067,\n",
       "         'left': -12.1079725,\n",
       "         'right': -6.247900000000001}}}}}},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.084661,\n",
       "    'left': 6.509843285714284,\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.044737,\n",
       "     'left': -2.544392714285715,\n",
       "     'right': 4.091626}}}}}"
      ]
     },
     "execution_count": 10,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "myDat2 = loadDataSet('ex2.txt')\n",
    "myMat2 = mat(myDat2)\n",
    "createTree(myMat2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "metadata": {},
   "outputs": [],
   "source": [
    "def isTree(obj):\n",
    "    return (type(obj).__name__ == 'dict')\n",
    "\n",
    "# 从根节点到叶节点计算平均值\n",
    "def getMean(tree):\n",
    "    if isTree(tree['right']):\n",
    "        tree['right'] = getMean(tree['right'])\n",
    "    if isTree(tree['left']):\n",
    "        tree['left'] = getMean(tree['left'])\n",
    "    return (tree['left'] + tree['right']) / 2.0\n",
    "\n",
    "# 剪枝函数\n",
    "# 参数 ：待剪枝的树，测试数据\n",
    "def prune(tree, testData):\n",
    "    if shape(testData)[0] == 0:\n",
    "        return getMean(tree)\n",
    "    \n",
    "    if (isTree(tree['right']) or isTree(tree['left'])):\n",
    "        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])\n",
    "    if isTree(tree['left']):\n",
    "        tree['left'] = prune(tree['left'], lSet)\n",
    "    if isTree(tree['right']):\n",
    "        tree['right'] = prune(tree['right'], rSet)\n",
    "        \n",
    "    # 完成剪枝后判断是否还是子树，不是的话判断能否进行合并剪枝操作\n",
    "    if not isTree(tree['left']) and not isTree(tree['right']):\n",
    "        lSet, rSet = binSplitDataSet(testData, tree['spInd'], tree['spVal'])\n",
    "        \n",
    "        errorNoMerge = sum(power(lSet[:, -1] - tree['left'], 2)) + \\\n",
    "        sum(power(rSet[:, -1] - tree['right'], 2))\n",
    "        \n",
    "        treeMean = (tree['left'] + tree['right']) / 2.0\n",
    "        errorMerge = sum(power(testData[:, -1] - treeMean, 2))\n",
    "        \n",
    "        if errorMerge < errorNoMerge:\n",
    "            print('merging')\n",
    "            return treeMean\n",
    "        else:\n",
    "            return tree\n",
    "    else:\n",
    "        return tree"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 待剪枝的树\n",
    "myTree = createTree(myMat2, ops=(0, 1))\n",
    "\n",
    "# 测试数据\n",
    "myDatTest = loadDataSet('ex2test.txt')\n",
    "myMat2Test = mat(myDatTest)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n",
      "merging\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "{'spInd': 0,\n",
       " 'spVal': 0.499171,\n",
       " 'left': {'spInd': 0,\n",
       "  'spVal': 0.729397,\n",
       "  'left': {'spInd': 0,\n",
       "   'spVal': 0.952833,\n",
       "   'left': {'spInd': 0,\n",
       "    'spVal': 0.965969,\n",
       "    'left': 92.5239915,\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.956951,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.958512,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.960398,\n",
       "       'left': 112.386764,\n",
       "       'right': 123.559747},\n",
       "      'right': 135.837013},\n",
       "     'right': 111.2013225}},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.759504,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.763328,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.769043,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.790312,\n",
       "       'left': {'spInd': 0,\n",
       "        'spVal': 0.806158,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.815215,\n",
       "         'left': {'spInd': 0,\n",
       "          'spVal': 0.833026,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.841547,\n",
       "           'left': {'spInd': 0,\n",
       "            'spVal': 0.841625,\n",
       "            'left': {'spInd': 0,\n",
       "             'spVal': 0.944221,\n",
       "             'left': {'spInd': 0,\n",
       "              'spVal': 0.948822,\n",
       "              'left': 96.41885225,\n",
       "              'right': 69.318649},\n",
       "             'right': {'spInd': 0,\n",
       "              'spVal': 0.85497,\n",
       "              'left': {'spInd': 0,\n",
       "               'spVal': 0.936524,\n",
       "               'left': 110.03503850000001,\n",
       "               'right': {'spInd': 0,\n",
       "                'spVal': 0.934853,\n",
       "                'left': 65.548418,\n",
       "                'right': {'spInd': 0,\n",
       "                 'spVal': 0.925782,\n",
       "                 'left': 115.753994,\n",
       "                 'right': {'spInd': 0,\n",
       "                  'spVal': 0.910975,\n",
       "                  'left': {'spInd': 0,\n",
       "                   'spVal': 0.912161,\n",
       "                   'left': 94.3961145,\n",
       "                   'right': 85.005351},\n",
       "                  'right': {'spInd': 0,\n",
       "                   'spVal': 0.901444,\n",
       "                   'left': {'spInd': 0,\n",
       "                    'spVal': 0.908629,\n",
       "                    'left': 106.814667,\n",
       "                    'right': 118.513475},\n",
       "                   'right': {'spInd': 0,\n",
       "                    'spVal': 0.901421,\n",
       "                    'left': 87.300625,\n",
       "                    'right': {'spInd': 0,\n",
       "                     'spVal': 0.892999,\n",
       "                     'left': {'spInd': 0,\n",
       "                      'spVal': 0.900699,\n",
       "                      'left': 100.133819,\n",
       "                      'right': 108.094934},\n",
       "                     'right': {'spInd': 0,\n",
       "                      'spVal': 0.888426,\n",
       "                      'left': 82.436686,\n",
       "                      'right': {'spInd': 0,\n",
       "                       'spVal': 0.872199,\n",
       "                       'left': 98.54454949999999,\n",
       "                       'right': 106.16859550000001}}}}}}}}},\n",
       "              'right': {'spInd': 0,\n",
       "               'spVal': 0.84294,\n",
       "               'left': {'spInd': 0,\n",
       "                'spVal': 0.847219,\n",
       "                'left': 89.20993,\n",
       "                'right': 76.240984},\n",
       "               'right': 95.893131}}},\n",
       "            'right': 60.552308},\n",
       "           'right': 124.87935300000001},\n",
       "          'right': {'spInd': 0,\n",
       "           'spVal': 0.823848,\n",
       "           'left': 76.723835,\n",
       "           'right': {'spInd': 0,\n",
       "            'spVal': 0.819722,\n",
       "            'left': 59.342323,\n",
       "            'right': 70.054508}}},\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.811602,\n",
       "          'left': 118.319942,\n",
       "          'right': {'spInd': 0,\n",
       "           'spVal': 0.811363,\n",
       "           'left': 99.841379,\n",
       "           'right': 112.981216}}},\n",
       "        'right': 73.49439925},\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.786865,\n",
       "        'left': 114.4008695,\n",
       "        'right': 102.26514075}},\n",
       "      'right': 64.041941},\n",
       "     'right': 115.199195},\n",
       "    'right': 78.08564325}},\n",
       "  'right': {'spInd': 0,\n",
       "   'spVal': 0.640515,\n",
       "   'left': {'spInd': 0,\n",
       "    'spVal': 0.642373,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.642707,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.665329,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.706961,\n",
       "       'left': {'spInd': 0,\n",
       "        'spVal': 0.70889,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.716211,\n",
       "         'left': 110.90283,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.710234,\n",
       "          'left': 103.345308,\n",
       "          'right': 108.553919}},\n",
       "        'right': 135.416767},\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.698472,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.69892,\n",
       "         'left': {'spInd': 0,\n",
       "          'spVal': 0.699873,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.70639,\n",
       "           'left': 106.180427,\n",
       "           'right': 105.062147},\n",
       "          'right': 115.586605},\n",
       "         'right': 92.470636},\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.689099,\n",
       "         'left': 120.521925,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.666452,\n",
       "          'left': 101.91115275,\n",
       "          'right': 112.78136649999999}}}},\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.661073,\n",
       "       'left': 121.980607,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.652462,\n",
       "        'left': 115.687524,\n",
       "        'right': 112.715799}}},\n",
       "     'right': 82.500766},\n",
       "    'right': 140.613941},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.613004,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.623909,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.628061,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.637999,\n",
       "       'left': 82.713621,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.632691,\n",
       "        'left': 91.656617,\n",
       "        'right': 93.645293}},\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.624827,\n",
       "       'left': 117.628346,\n",
       "       'right': 105.970743}},\n",
       "     'right': 82.04976400000001},\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.606417,\n",
       "     'left': 168.180746,\n",
       "     'right': {'spInd': 0,\n",
       "      'spVal': 0.513332,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.533511,\n",
       "       'left': {'spInd': 0,\n",
       "        'spVal': 0.548539,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.553797,\n",
       "         'left': {'spInd': 0,\n",
       "          'spVal': 0.560301,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.599142,\n",
       "           'left': 93.521396,\n",
       "           'right': {'spInd': 0,\n",
       "            'spVal': 0.589806,\n",
       "            'left': 130.378529,\n",
       "            'right': {'spInd': 0,\n",
       "             'spVal': 0.582311,\n",
       "             'left': 111.9849935,\n",
       "             'right': {'spInd': 0,\n",
       "              'spVal': 0.571214,\n",
       "              'left': 82.589328,\n",
       "              'right': {'spInd': 0,\n",
       "               'spVal': 0.569327,\n",
       "               'left': 114.872056,\n",
       "               'right': 108.435392}}}}},\n",
       "          'right': 82.903945},\n",
       "         'right': 129.0624485},\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.546601,\n",
       "         'left': 83.114502,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.537834,\n",
       "          'left': 97.3405265,\n",
       "          'right': 90.995536}}},\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.51915,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.531944,\n",
       "         'left': 129.766743,\n",
       "         'right': 124.795495},\n",
       "        'right': 116.176162}},\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.508548,\n",
       "       'left': 101.075609,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.508542,\n",
       "        'left': 93.292829,\n",
       "        'right': 96.403373}}}}}}},\n",
       " 'right': {'spInd': 0,\n",
       "  'spVal': 0.457563,\n",
       "  'left': {'spInd': 0,\n",
       "   'spVal': 0.465561,\n",
       "   'left': {'spInd': 0,\n",
       "    'spVal': 0.467383,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.483803,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.487381,\n",
       "      'left': 8.53677,\n",
       "      'right': 27.729263},\n",
       "     'right': 5.224234},\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.46568,\n",
       "     'left': -9.712925,\n",
       "     'right': -23.777531}},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.463241,\n",
       "    'left': 30.051931,\n",
       "    'right': 17.171057}},\n",
       "  'right': {'spInd': 0,\n",
       "   'spVal': 0.455761,\n",
       "   'left': -34.044555,\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.126833,\n",
       "    'left': {'spInd': 0,\n",
       "     'spVal': 0.130626,\n",
       "     'left': {'spInd': 0,\n",
       "      'spVal': 0.382037,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.388789,\n",
       "       'left': {'spInd': 0,\n",
       "        'spVal': 0.437652,\n",
       "        'left': -4.1911745,\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.412516,\n",
       "         'left': {'spInd': 0,\n",
       "          'spVal': 0.418943,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.426711,\n",
       "           'left': {'spInd': 0,\n",
       "            'spVal': 0.428582,\n",
       "            'left': 19.745224,\n",
       "            'right': 15.224266},\n",
       "           'right': -21.594268},\n",
       "          'right': 44.161493},\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.403228,\n",
       "          'left': -26.419289,\n",
       "          'right': 0.6359300000000001}}},\n",
       "       'right': 23.197474},\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.335182,\n",
       "       'left': {'spInd': 0,\n",
       "        'spVal': 0.370042,\n",
       "        'left': {'spInd': 0,\n",
       "         'spVal': 0.378965,\n",
       "         'left': -29.007783,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.373501,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.377383,\n",
       "           'left': 13.583555,\n",
       "           'right': 5.241196},\n",
       "          'right': -8.228297}},\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.35679,\n",
       "         'left': -32.124495,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.350725,\n",
       "          'left': -9.9938275,\n",
       "          'right': -26.851234812500003}}},\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.324274,\n",
       "        'left': 22.286959625,\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.309133,\n",
       "         'left': {'spInd': 0,\n",
       "          'spVal': 0.310956,\n",
       "          'left': -20.3973335,\n",
       "          'right': -49.939516},\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.131833,\n",
       "          'left': {'spInd': 0,\n",
       "           'spVal': 0.138619,\n",
       "           'left': {'spInd': 0,\n",
       "            'spVal': 0.156067,\n",
       "            'left': {'spInd': 0,\n",
       "             'spVal': 0.166765,\n",
       "             'left': {'spInd': 0,\n",
       "              'spVal': 0.193282,\n",
       "              'left': {'spInd': 0,\n",
       "               'spVal': 0.211633,\n",
       "               'left': {'spInd': 0,\n",
       "                'spVal': 0.228473,\n",
       "                'left': {'spInd': 0,\n",
       "                 'spVal': 0.25807,\n",
       "                 'left': {'spInd': 0,\n",
       "                  'spVal': 0.284794,\n",
       "                  'left': {'spInd': 0,\n",
       "                   'spVal': 0.300318,\n",
       "                   'left': 8.814725,\n",
       "                   'right': {'spInd': 0,\n",
       "                    'spVal': 0.297107,\n",
       "                    'left': -18.051318,\n",
       "                    'right': {'spInd': 0,\n",
       "                     'spVal': 0.295993,\n",
       "                     'left': -1.798377,\n",
       "                     'right': {'spInd': 0,\n",
       "                      'spVal': 0.290749,\n",
       "                      'left': -14.988279,\n",
       "                      'right': -14.391613}}}},\n",
       "                  'right': {'spInd': 0,\n",
       "                   'spVal': 0.273863,\n",
       "                   'left': 35.623746,\n",
       "                   'right': {'spInd': 0,\n",
       "                    'spVal': 0.264926,\n",
       "                    'left': -9.457556,\n",
       "                    'right': {'spInd': 0,\n",
       "                     'spVal': 0.264639,\n",
       "                     'left': 5.280579,\n",
       "                     'right': 2.557923}}}},\n",
       "                 'right': {'spInd': 0,\n",
       "                  'spVal': 0.228628,\n",
       "                  'left': {'spInd': 0,\n",
       "                   'spVal': 0.228751,\n",
       "                   'left': -9.601409499999999,\n",
       "                   'right': -30.812912},\n",
       "                  'right': -2.266273}},\n",
       "                'right': 6.099239},\n",
       "               'right': {'spInd': 0,\n",
       "                'spVal': 0.202161,\n",
       "                'left': -16.42737025,\n",
       "                'right': -2.6781805}},\n",
       "              'right': 9.5773855},\n",
       "             'right': {'spInd': 0,\n",
       "              'spVal': 0.156273,\n",
       "              'left': {'spInd': 0,\n",
       "               'spVal': 0.164134,\n",
       "               'left': {'spInd': 0,\n",
       "                'spVal': 0.166431,\n",
       "                'left': -14.740059,\n",
       "                'right': -6.512506},\n",
       "               'right': -27.405211},\n",
       "              'right': 0.225886}},\n",
       "            'right': {'spInd': 0,\n",
       "             'spVal': 0.13988,\n",
       "             'left': 7.557349,\n",
       "             'right': 7.336784}},\n",
       "           'right': -29.087463},\n",
       "          'right': 22.478291}}}}},\n",
       "     'right': -39.524461},\n",
       "    'right': {'spInd': 0,\n",
       "     'spVal': 0.124723,\n",
       "     'left': 22.891675,\n",
       "     'right': {'spInd': 0,\n",
       "      'spVal': 0.085111,\n",
       "      'left': {'spInd': 0,\n",
       "       'spVal': 0.108801,\n",
       "       'left': 6.196516,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.10796,\n",
       "        'left': -16.106164,\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.085873,\n",
       "         'left': -1.293195,\n",
       "         'right': -10.137104}}},\n",
       "      'right': {'spInd': 0,\n",
       "       'spVal': 0.084661,\n",
       "       'left': 37.820659,\n",
       "       'right': {'spInd': 0,\n",
       "        'spVal': 0.080061,\n",
       "        'left': -24.132226,\n",
       "        'right': {'spInd': 0,\n",
       "         'spVal': 0.068373,\n",
       "         'left': 15.824970500000001,\n",
       "         'right': {'spInd': 0,\n",
       "          'spVal': 0.061219,\n",
       "          'left': -15.160836,\n",
       "          'right': {'spInd': 0,\n",
       "           'spVal': 0.044737,\n",
       "           'left': {'spInd': 0,\n",
       "            'spVal': 0.053764,\n",
       "            'left': {'spInd': 0,\n",
       "             'spVal': 0.055862,\n",
       "             'left': 6.695567,\n",
       "             'right': -3.131497},\n",
       "            'right': -13.731698},\n",
       "           'right': 4.091626}}}}}}}}}}}"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "prune(myTree, myMat2Test)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 模型树"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 数据格式化及构建线性回归方程\n",
    "def linearSolve(dataSet):\n",
    "    m, n = shape(dataSet)\n",
    "    \n",
    "    # 数据格式化\n",
    "    X = mat(ones((m, n)))\n",
    "    Y = mat(ones((m, 1)))\n",
    "    X[:, 1:n] = dataSet[:, 0:n-1]\n",
    "    Y = dataSet[:, -1]\n",
    "    \n",
    "    xTx = X.T * X\n",
    "    if linalg.det(xTx) == 0.0:\n",
    "        raise NameError('This matrix is singular, cannot do inverse, try \\\n",
    "        increasing the second value of ops')\n",
    "    ws = xTx.T * (X.T * Y)\n",
    "    return ws, X, Y\n",
    "\n",
    "# 生成叶节点\n",
    "def modelLeaf(dataSet):\n",
    "    ws, X, Y = linearSolve(dataSet)\n",
    "    return ws\n",
    "\n",
    "# 计算平方误差\n",
    "def modelErr(dataSet):\n",
    "    ws, X, Y = linearSolve(dataSet)\n",
    "    yHat = X * ws\n",
    "    return sum(power(Y - yHat, 2))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{'spInd': 0,\n",
       " 'spVal': 0.66897,\n",
       " 'left': {'spInd': 0,\n",
       "  'spVal': 0.829402,\n",
       "  'left': {'spInd': 0, 'spVal': 0.906907, 'left': matrix([[4975.08130668],\n",
       "           [4787.84869266]]), 'right': matrix([[5338.48156289],\n",
       "           [4668.13806435]])},\n",
       "  'right': {'spInd': 0, 'spVal': 0.763717, 'left': matrix([[5105.00607177],\n",
       "           [4086.18045627]]), 'right': {'spInd': 0,\n",
       "    'spVal': 0.721517,\n",
       "    'left': matrix([[1387.78024516],\n",
       "            [1034.39811056]]),\n",
       "    'right': matrix([[1254.1632993 ],\n",
       "            [ 882.47514671]])}}},\n",
       " 'right': {'spInd': 0,\n",
       "  'spVal': 0.399447,\n",
       "  'left': {'spInd': 0,\n",
       "   'spVal': 0.551771,\n",
       "   'left': {'spInd': 0, 'spVal': 0.609194, 'left': matrix([[1583.44942959],\n",
       "            [1022.20757928]]), 'right': matrix([[1367.76302312],\n",
       "            [ 806.73069721]])},\n",
       "   'right': {'spInd': 0, 'spVal': 0.501156, 'left': matrix([[1355.66970295],\n",
       "            [ 713.53111618]]), 'right': matrix([[1456.36098645],\n",
       "            [ 653.00187841]])}},\n",
       "  'right': {'spInd': 0,\n",
       "   'spVal': 0.212118,\n",
       "   'left': {'spInd': 0, 'spVal': 0.30971, 'left': matrix([[1579.42995062],\n",
       "            [ 571.34790715]]), 'right': matrix([[1447.72283356],\n",
       "            [ 386.80380246]])},\n",
       "   'right': {'spInd': 0,\n",
       "    'spVal': 0.117348,\n",
       "    'left': {'spInd': 0, 'spVal': 0.181268, 'left': matrix([[392.43161013],\n",
       "             [ 75.23557749]]), 'right': matrix([[370.60218539],\n",
       "             [ 56.529874  ]])},\n",
       "    'right': {'spInd': 0, 'spVal': 0.059849, 'left': matrix([[358.47984395],\n",
       "             [ 29.92453779]]), 'right': matrix([[422.03935523],\n",
       "             [ 10.81947907]])}}}}}"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "myMat2 = mat(loadDataSet('exp2.txt'))\n",
    "createTree(myMat2, modelLeaf, modelErr, (1, 10))"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 树回归与标准回归的比较"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 返回叶节点数据\n",
    "def regTreeEval(model, inDat):\n",
    "    return float(model)\n",
    "\n",
    "def modelTreeEval(model, inDat):\n",
    "    n = shape(inDat)[1]  # 特征数\n",
    "    X = mat(ones((1, n+1)))\n",
    "    X[:, 1:n+1] = inDat\n",
    "    return float(X * model)\n",
    "\n",
    "# 对单个测试数据进行预测\n",
    "def treeForeCast(tree, inData, modelEval=regTreeEval):\n",
    "    if not isTree(tree):\n",
    "        return modelEval(tree, inData)\n",
    "    # 比较对应的特征值大小\n",
    "    if inData[tree['spInd']] > tree['spVal']:  # 该特征对应的值大时\n",
    "        if isTree(tree['left']):\n",
    "            return treeForeCast(tree['left'], inData, modelEval)\n",
    "        else:\n",
    "            return modelEval(tree['left'], inData)\n",
    "    else:\n",
    "        if isTree(tree['right']):\n",
    "            return treeForeCast(tree['right'], inData, modelEval)\n",
    "        else:\n",
    "            return modelEval(tree['right'], inData)\n",
    "\n",
    "# 根据传入的树和测试数据返回预测结果\n",
    "def createForeCast(tree, testData, modelEval=regTreeEval):\n",
    "    m = len(testData)\n",
    "    yHat = mat(zeros((m, 1)))\n",
    "    for i in range(m):\n",
    "        yHat[i, 0] = treeForeCast(tree, mat(testData[i]), modelEval)\n",
    "    return yHat"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9640852318222145"
      ]
     },
     "execution_count": 17,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 回归树\n",
    "trainMat = mat(loadDataSet('bikeSpeedVsIq_train.txt'))\n",
    "testMat = mat(loadDataSet('bikeSpeedVsIq_test.txt'))\n",
    "\n",
    "myTree = createTree(trainMat, ops=(1, 20))\n",
    "yHat = createForeCast(myTree, testMat[:, 0])\n",
    "\n",
    "corrcoef(yHat, testMat[:, 1], rowvar=0)[0, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.7235743421633926"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 模型树\n",
    "myTree = createTree(trainMat, modelLeaf, modelErr, (1, 20))\n",
    "yHat = createForeCast(myTree, testMat[:, 0], modelTreeEval)\n",
    "\n",
    "corrcoef(yHat, testMat[:, 1], rowvar=0)[0, 1]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "matrix([[7.15176501e+08],\n",
       "        [1.10177289e+10]])"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 标准线性回归\n",
    "ws, X, Y = linearSolve(trainMat)\n",
    "ws"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "0.9434684235674762"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "for i in range(shape(testMat)[0]):\n",
    "    yHat[i] = testMat[i, 0] * ws[1, 0] + ws[0, 0]\n",
    "    \n",
    "corrcoef(yHat, testMat[:, 1], rowvar=0)[0, 1]"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "### 使用Tkinter库创建GUI"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "metadata": {},
   "outputs": [],
   "source": [
    "from tkinter import *\n",
    "import matplotlib\n",
    "from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg\n",
    "from matplotlib.figure import Figure"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 22,
   "metadata": {},
   "outputs": [],
   "source": [
    "# root = Tk()\n",
    "# myLabel = Label(root, text='hello world')\n",
    "# myLabel.grid()\n",
    "# root.mainloop()"
   ]
  },
  {
   "attachments": {
    "%E5%9B%BE%E7%89%87.png": {
     "image/png": "iVBORw0KGgoAAAANSUhEUgAAAJQAAAA8CAYAAACAc5NXAAAEz0lEQVR4nO2bTU8bVxiF50ewY9sPqatKgVGktqKlgTSiTas2qJAKMkAN4TNBQEwQYIW0HSpEoVWV1sVpBaSV2mFVdcnGf8CwYsGCFTsLDEQCFuDThcfYMx6bMfNCGHwe6Uhga+5979zH914PQgEhgiivugBytaBQRBQKRUShUESUcxFqdXUVD/v7MTIych7Nk0uMqFD7+/v4xzDQ2hvEvdALPAoOSzZPfICYUIlEAs2ahrYHj1E38AK1/X9h6BGFKjVEhNrd3UVndzeGvp9D8/ifqAws4JPun/D89z8kmic+QkQofXIST2bmUN27gNqOWVQGFlBzpx2bm5sSzRMf4Vmora0tDI2MorZvHre7fsD7zU9R0/ItGptaJOoTIRwOu4rfCYfDiMfjed+Px+PnPk5PQh0eHqK7pxsPR7/Drd7fUFlVh4q2edQEZjH+RJeq0TNubuJVECoej2MuEnGUqtB7kngSan19HQ1NrRic/hu36gN4p2Ec19sXUV3/AGtra1I1eqZUhAKcxbkomQCPQs3MzKItOI3GYATv3fwCFW3zeLf1R3T1P8bBwYFUjZ4pJaEAq0AXKRPgUai29vsYnPkXH9b3oOruOCoDC7jRHEIk8hzJZFKqRs+UmlBARqqLlAkwhTrLofX4+BgNWgBdU//h2gd3cK3pZ1xv+QX9g8PY29u7sAG4gUJdsFBnYWVlBR9/fhe9kwZuftmDCu1XfNqhY2Ji4lKtTkDpCeXLLW9qagqtnX0Y+OYZ6poGUNkaQWPHCJaXlyXrE6GUhPLtoTwajeJ+Ty9GQ09R9VkHPup8hq/ufY2XL19K1idCqQjl68cGyWQSweAwXnv9Dbz51tuovlGLRCIhWZsYfLCZ4tI/2DQMA+Xl5SgrK0M0GpWqifgYT0IdHR2hr68PY2Njl+4gTl4NnoRKJpMIhUJYXFyUqof4HM9/HJ6ensbS0pJELeQK4Fmo7e1tbGxsSNRCrgD8JwUiCoUiolAoIgqFIqJQKCIKhSKiUCgiCoUiolAoIoqys7MDhpEKhWJEQ6EY0VAoRjQUihENhWJEQ6EY0eQIZWgKFM3w3LChKVBUHbE8v/sl7uqOQVdl7pvfQ6GKHIdzKFQ6FKrIcTiHQqVDoYoch3MoVDp5hYrpKhRFMaPBsF8c06GevJ97010JZW9DUaAZxU1u3teyJ9dFP+l2jPS4zTYd6zY0S1uKplOogkIpClQ9Zr5mQLMLY2hQFBV6LH2d+QktIFDOxJiTYplYc+IzfduS069Zm0MtJ+267Cc9brsUburOd20pxlko2ycytVqlVynbhFkmKTOxhYVKieAkjrUve1LXWWVRoapZbVnqcN9PSorcft3VzS2vsFC2G2O5+Q7bh9NWUlAosw3H7S1nFcpfX0xXM9uz2Xb2z8X0k++s5K5uCuVZqEJnnfMUKiNM1koZ06Ga9RmafbWiUJdbqALbiGuhzrzl7WS2NCMjUWYbNqA5nLFcb3mnCZW3PfMsR6HOItTOyTfAnINu1nWnHcod23A6QOfElEfTLHWmVi4VquP57/R+3AmVPmtZV1Aeyj0KlT1Rnh4b2L9+F9jqcusp4huii37cCmUR6OTcyC0vr1AM4yUUihENhWJEQ6EY0VAoRjQUihENhWJE8z8VNu3Vw2sTqQAAAABJRU5ErkJggg=="
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![%E5%9B%BE%E7%89%87.png](attachment:%E5%9B%BE%E7%89%87.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 31,
   "metadata": {},
   "outputs": [],
   "source": [
    "# 绘图\n",
    "def reDraw(tolS, tolN):\n",
    "    reDraw.f.clf()  # 清空原图\n",
    "    reDraw.a = reDraw.f.add_subplot(111)\n",
    "    if chkBtnVar.get():  # 复选框被选中\n",
    "        if tolN < 2:\n",
    "            tolN = 2\n",
    "        myTree = createTree(reDraw.rawDat, modelLeaf, modelErr, (tolS, tolN))\n",
    "        yHat = createForeCast(myTree, reDraw.testDat, modelTreeEval)\n",
    "    else:\n",
    "        myTree = createTree(reDraw.rawDat, ops=(tolS, tolN))\n",
    "        yHat = createForeCast(myTree, reDraw.testDat)\n",
    "    reDraw.a.scatter(reDraw.rawDat[:, 0].tolist(), reDraw.rawDat[:, 1].tolist(), s=5)\n",
    "    reDraw.a.plot(reDraw.testDat, yHat, linewidth=2.0)\n",
    "    reDraw.canvas.draw()\n",
    "\n",
    "# 获取输入框中的值\n",
    "def getInputs():\n",
    "    try:\n",
    "        tolN = int(tolNentry.get())\n",
    "    except:\n",
    "        tolN = 10\n",
    "        print('enter Integer for tolN')\n",
    "        tolNentry.delete(0, END)\n",
    "        tolNentry.insert(0, 10)\n",
    "    try:\n",
    "        tolS = float(tolSentry.get())\n",
    "    except:\n",
    "        tolS = 1.0\n",
    "        print('enter Float for tolS')\n",
    "        tolSentry.delete(0, END)\n",
    "        tolSentry.insert(0, '1.0')\n",
    "    return tolN, tolS\n",
    "\n",
    "def drawNewTree():\n",
    "    tolN, tolS = getInputs()  # 获取输入框中的值\n",
    "    reDraw(tolS, tolN)  # 绘图\n",
    "\n",
    "root = Tk()\n",
    "Label(root, text='Plot Place Holder').grid(row=0, columnspan=3)\n",
    "# 第一个输入框\n",
    "Label(root, text='tolN').grid(row=1, column=0)\n",
    "tolNentry = Entry(root)\n",
    "tolNentry.grid(row=1, column=1)\n",
    "tolNentry.insert(0, '10')\n",
    "# 第二个输入框\n",
    "Label(root, text='tolS').grid(row=2, column=0)\n",
    "tolSentry = Entry(root)\n",
    "tolSentry.grid(row=2, column=1)\n",
    "tolSentry.insert(0, '1.0')\n",
    "# 绘制按钮\n",
    "Button(root, text='ReDraw', command=drawNewTree).grid(row=1, column=2, rowspan=3)\n",
    "# 复选框\n",
    "chkBtnVar = IntVar()\n",
    "chkBtn = Checkbutton(root, text='model tree', variable=chkBtnVar)\n",
    "chkBtn.grid(row=3, column=0, columnspan=2)\n",
    "\n",
    "# 画布\n",
    "reDraw.f = Figure(figsize=(5, 4), dpi=100)\n",
    "reDraw.canvas = FigureCanvasTkAgg(reDraw.f, master=root)\n",
    "reDraw.canvas.draw()\n",
    "reDraw.canvas.get_tk_widget().grid(row=0, columnspan=3)\n",
    "\n",
    "reDraw.rawDat = mat(loadDataSet('sine.txt'))\n",
    "reDraw.testDat = arange(min(reDraw.rawDat[:, 0]), max(reDraw.rawDat[:, 0]), 0.01)\n",
    "reDraw(1.0, 10)\n",
    "\n",
    "root.mainloop()"
   ]
  },
  {
   "attachments": {
    "%E5%9B%BE%E7%89%87.png": {
     "image/png": "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AADAAAJdxcKFC6lz587UqVMn6tWrF23evNnp83NycqhXr17UqVMnuu2222jx4sUBamngebJs1q9fT08++ST94Q9/oJtuuokefvhhSk1NDWBrA8vTz41NXl4eXXPNNdSzZ08/t1A7ni6bxsZGGjt2LP3lL3+hjh07UpcuXWj58uUBam3geLpcVq9eTffddx9df/31dMstt9DQoUPp/PnzAWpt4OTm5tLzzz9Pt956K5lMJtqwYYPL1wTTdlgJAl3BmjVrqEOHDrRs2TIqLS2lUaNG0Y033kjHjh1TfP7hw4fphhtuoFGjRlFpaSktW7aMOnToQOvWrQtwy/3P02UzatQoiomJoe3bt1NlZSWNGTOGOnToQEVFRQFuuf95umxsamtrqUuXLvT000+zDXRvls2AAQPooYceooyMDDpy5Aht27aN8vPzA9hq//N0uWzZsoV++9vf0pdffkmHDx+mLVu20N13300vvfRSgFvuf8nJyTRu3Dhav369W4EeTNthNQh0BaGhoTR8+HDJY927d6eIiAjF53/xxRfUvXt3yWPDhg2jhx9+2G9t1Iqny0bJXXfdRZMnT/Z10zTn7bJ57bXXaPz48RQZGck20D1dNikpKXTzzTdTTU1NIJqnGU+Xy6xZs6hLly6Sx+bNm0d//vOf/dZGPXAn0INpO6wGgS7T1NRE11xzDSUkJEgeHzlyJPXr10/xNX379qWRI0dKHktISKBrr72Wmpub/dbWQPNm2chZLBb6f//v/9H8+fP90UTNeLtsvvnmG+rduze1tLSwDXRvls2IESPoiSeeoPDwcPrf//1f6tq1K3322Wd09erVQDQ5ILxZLvn5+dSxY0dKSkoiq9VKp0+fpn79+tGwYcMC0WTNuBPowbIddgaBLnPy5EkymUwOh/aioqLozjvvVHxN165dKSoqSvJYfn4+mUwmOnXqlN/aGmjeLBu5mTNn0n//93/TmTNn/NFEzXizbCorK+l//ud/qKKigoiIbaB7s2yeeeYZ6tSpEz333HO0bds2SkpKopCQEHr77bcD0eSA8HZ9io+Pp9/97nd07bXXkslkogEDBrAPLHcCPVi2w84g0GVsK1lBQYHk8WnTplG3bt0UX9O1a1eaPn265LG8vDwymUxUXV3tt7YGmjfLRuyHH36gG264gTIyMvzVRM14umzMZjP17t1bMmiHe6B7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"
    }
   },
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "![%E5%9B%BE%E7%89%87.png](attachment:%E5%9B%BE%E7%89%87.png)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 32,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "3.7.5 (default, Oct 31 2019, 15:18:51) [MSC v.1916 64 bit (AMD64)]\n"
     ]
    }
   ],
   "source": [
    "import sys\n",
    "print(sys.version)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.7.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
